import {
  Box,
  DragAndDropProvider,
  DraggableItem,
  DragHandle,
  DroppableContainer,
  Expandable,
  Icon,
  PopoverConfirm,
  SimpleEditor,
  useCall,
  useEffectState,
} from '@/components';
import DescEditor from '@/pages/Comparison/CompareProduct/components/DescEditor';
import FormulaEditor from '@/pages/Comparison/CompareProduct/components/FormulaEditor';
import { forkHandler, mergeState, uid } from '@/utils';
import { get, pull, set } from '@/utils/fp';
import { Button, Input, message, Space } from 'antd';
import clsx from 'clsx';
import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
import styles from '../index.less';

const EditRow = ({ index, data, onChange, onRemove, onAdd, onEdit, editing, level = 0 }) => {
  const [state, setState] = useEffectState(data);

  const update = useCall((name, value) => {
    setState((prev) => mergeState({ ...prev }, { [name]: value }));
  });
  const isEditing = editing?.[0] === data;
  const toggle = useCall(() => onEdit(isEditing ? null : data));

  const stateRef = useRef();
  stateRef.current = state;
  const onSave = useCall(forkHandler(toggle, () => onChange(stateRef.current, index), true));
  const onCancel = useCall(() => {
    onEdit(null);
    if (data.id) {
      setState(data);
    } else {
      onRemove(data, index);
    }
  });

  const changeName = useCall((e) => {
    update('benefitName', e.target.value);
  });
  const changeDesc = useCall((value) => update('benefitDesc', value));
  const changeFormula = useCall((value) => update('benefitFormula', value));

  const handleRemove = useCall(() => {
    if (data.children?.length) {
      message.warn('请先删除子节点');
    } else {
      return onRemove(data, index);
    }
  });

  const onAddChild = useCall(onAdd, data);

  useEffect(() => {
    if (editing === data) onEdit([data, onSave]);
  }, [editing]);

  return (
    <DraggableItem row={data}>
      <div className={clsx(styles.tableCell, { [styles.editing]: isEditing })} style={{ width: 64 }}>
        {isEditing ? (
          <Space direction='vertical' size={4}>
            <Button size='small' type='link' onClick={onSave}>
              保存
            </Button>
            <Button size='small' type='text' onClick={onCancel}>
              取消
            </Button>
          </Space>
        ) : (
          <DragHandle>
            <Button size='small' type='text'>
              <Icon type='menu' />
            </Button>
          </DragHandle>
        )}
      </div>
      <div className={clsx(styles.tableCell, { [styles.editing]: isEditing })} style={{ width: 200 }}>
        {isEditing ? (
          <Input defaultValue={state.benefitName} onChange={changeName} autoFocus={level === 0} />
        ) : (
          <Space size={4} className={styles.info} wrap>
            <span>{state.benefitName}</span>
            <Button size='small' type='text' className={styles.editIcon} onClick={toggle}>
              <Icon type='edit' />
            </Button>
            <PopoverConfirm onOk={handleRemove}>
              <Button size='small' type='text' className={styles.editIcon} danger>
                <Icon type='delete' />
              </Button>
            </PopoverConfirm>
          </Space>
        )}
      </div>
      {level === 0 ? (
        <div className={styles.tableCell} style={{ padding: 0, flex: 1 }}>
          {state.children.map((row, i) => (
            <EditRow
              key={row.benefitCode}
              index={`${index}.children.${i}`}
              data={row}
              onChange={onChange}
              onRemove={onRemove}
              onAdd={onAdd}
              onEdit={onEdit}
              editing={editing}
              level={level + 1}
            />
          ))}
          {state.id && (
            <Expandable expanded={!editing}>
              <Expandable.Content>
                <Box px={2} py={2}>
                  <Button type='primary' ghost size='small' onClick={onAddChild}>
                    +新增二级描述
                  </Button>
                </Box>
              </Expandable.Content>
            </Expandable>
          )}
        </div>
      ) : (
        <div className={clsx(styles.tableCell, { [styles.editing]: isEditing })} style={{ flex: 1 }}>
          {isEditing ? (
            <div>
              <FormulaEditor value={state.benefitFormula} onChange={changeFormula} />
              <DescEditor value={state.benefitDesc} onChange={changeDesc} editing />
            </div>
          ) : (
            <Space size={4} direction='vertical' className={styles.info}>
              <FormulaEditor value={state.benefitFormula} readOnly />
              <div dangerouslySetInnerHTML={{ __html: state.benefitDesc }} />
              <Button size='small' type='text' className={styles.editIcon} onClick={toggle}>
                <Icon type='edit' />
              </Button>
            </Space>
          )}
        </div>
      )}
    </DraggableItem>
  );
};

BenefitDescTable = forwardRef(BenefitDescTable);

function BenefitDescTable(props, ref) {
  const { dataSource, type = '0', planCode, productCode, onChange: propOnChange, onRemove: propOnRemove } = props;
  const [state, setState] = useEffectState(dataSource ?? useRef([]).current);
  const [editing, onEdit] = useState();

  const getListByParentCode = (parentCode, list = state) => {
    if (parentCode === '0') return list;
    return state.find((v) => v.benefitCode === parentCode)?.children ?? list;
  };

  const onChange = useCall((item, index) => {
    const indexes = index.split('.');
    setState((prev) => {
      const next = prev.slice(0);
      set(next, indexes)(item);
      return next;
    });
    const { children, ...updateItem } = item;
    return propOnChange?.([updateItem]);
  });

  const onSave = useCall(() => {
    return editing?.[1]();
  });

  useImperativeHandle(
    ref,
    () => ({
      onSave,
    }),
    [],
  );

  const onAdd = useCall((parent) => {
    const newItem = {
      id: null,
      benefitCode: uid(),
      parentCode: parent ? parent.benefitCode : '0',
      benefitName: '',
      benefitDesc: '',
      isShow: '1',
      layer: parent ? 2 : 1,
      type,
      planCode,
      productCode,
      children: [],
    };
    (parent?.children ?? state).push(newItem);
    setState(state.slice());
    onEdit(newItem);
  });

  const handleRemove = (item, index) => {
    const indexes = index.split('.');
    const popIndex = indexes.pop();

    setState((prev) => {
      let next = prev.slice();
      if (indexes.length) {
        const list = get(indexes)(next);
        const nextList = pull(item)(list);
        set(next, indexes)(nextList);
      } else {
        next = pull(item)(next);
      }
      return next;
    });
  };

  const onRemove = useCall(forkHandler(propOnRemove, handleRemove, true));

  const getDroppableKeys = useCall((allCtxMap, draggingCtx) => {
    onEdit(null);
    return getListByParentCode(draggingCtx.row.parentCode).map((v) => v.benefitCode);
  });

  const onDrop = useCall((itemCtx, index) => {
    let list = [];
    setState((prev) => {
      const next = prev.slice();
      list = getListByParentCode(itemCtx.row.parentCode, next);
      const [item] = list.splice(itemCtx.index, 1);
      list.splice(index, 0, item);

      return next;
    });

    let shouldUpdate = false;
    const result = list.map(({ children, on, ...item }, index) => {
      shouldUpdate = shouldUpdate || index !== on;
      return { ...item, on: index };
    });

    if (shouldUpdate) return propOnChange?.(result);
  });

  const onAddRoot = useCall(onAdd, null);

  const lastRow = (
    <Expandable expanded={!editing}>
      <Expandable.Content>
        <div className={styles.tableCell} style={{ flexGrow: 1 }}>
          <div>
            <Button type='primary' onClick={onAddRoot}>
              +新增一级描述
            </Button>
          </div>
        </div>
      </Expandable.Content>
    </Expandable>
  );

  return (
    <DragAndDropProvider
      rowKey='benefitCode'
      itemClassName={styles.tableRow}
      itemDraggingClassName={styles.dragging}
      containerClassName={styles.benefitTable}
      getDroppableKeys={getDroppableKeys}
      onDrop={onDrop}
    >
      <DroppableContainer>
        <div className={styles.tableHead}>
          <div className={styles.tableCell} style={{ width: 64 }} children='排序' />
          <div className={styles.tableCell} style={{ width: 200 }} children='利益描述名称（一级）' />
          <div className={styles.tableCell} style={{ width: 64 }} children='排序' />
          <div className={styles.tableCell} style={{ width: 200 }} children='利益描述名称（二级）' />
          <div className={styles.tableCell} style={{ flexGrow: 1 }} children='利益描述内容' />
        </div>
        {state?.length ? (
          <div className={styles.tableBody}>
            {state.map((row, index) => (
              <EditRow
                key={row.benefitCode}
                index={`${index}`}
                data={row}
                onChange={onChange}
                onRemove={onRemove}
                onAdd={onAdd}
                onEdit={onEdit}
                editing={editing}
              />
            ))}
            {lastRow}
          </div>
        ) : (
          lastRow
        )}
      </DroppableContainer>
    </DragAndDropProvider>
  );
}

export default BenefitDescTable;
